#include <thread>
#include <condition_variable>
#include <mutex>
#include <iostream>
#include <chrono>
#include <queue>
#include <syslog.h>
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

using namespace std;

std::mutex mtlock;
std::condition_variable cvlock;

//#define TEST1

bool isReady = false;
int iValue = 0;
const int THREAD_NUM = 10;
queue<int> temp;
const int MAX_SIZE = 2;
    
//生产者线程数量
const int NUM_THREAD_P = 10;
//消费者线程数量
const int NUM_THREAD_C = 1;

//生产者函数
void Productor(int i);
//消费者函数
void Cousomer(int i);
//线程测试函数
void ThreadTest(int index);
//开始函数
void go();

int main()
{
    char charTemp[128] = {0x00};
    sprintf(charTemp,"条件变量测试");
    cout<<charTemp<<endl;
    this_thread::sleep_for(std::chrono::microseconds(3000));
    openlog("test theread",LOG_CONS|LOG_PID,LOG_LOCAL3);
    syslog(LOG_INFO,charTemp);

#ifdef TEST1

    std::thread tP[THREAD_NUM]; 

    //生产者线程
    for(int i =0; i< THREAD_NUM;i++)
        tP[i] = std::thread(ThreadTest,i);

    this_thread::sleep_for(std::chrono::milliseconds(3000));
    cout<<"统一信号"<<endl;
    go();

    for(int i = 0;i< THREAD_NUM;i++)
        tP[i].join();

#else
    //生产者线程句柄
    std::thread tP[NUM_THREAD_P];
    //消费者线程句柄
    std::thread tC[NUM_THREAD_C];

    //生产者线程
    sprintf(charTemp,"创建生产者线程");
    cout<<charTemp<<endl;
    for(int i =0; i< NUM_THREAD_P;i++)
        tP[i] = std::thread(Productor,i);

    this_thread::sleep_for(std::chrono::milliseconds(10000));

    //消费者线程
    sprintf(charTemp,"创建消费者线程");
    cout<<charTemp<<endl;
    for(int i = 0; i< NUM_THREAD_C;i++)
        tC[i] = std::thread(Cousomer,i);


    for(int i = 0;i< NUM_THREAD_P;i++)
        tP[i].join();

    for(int i = 0; i< NUM_THREAD_C;i++)
       tC[i].join();


#endif
    return 0;
}


void Productor(int index)
{
    char charTemp[128];
    int count = 0;
    int writeVal = 0;
    
    bzero(charTemp,128);
    sprintf(charTemp,"第[%d]号生产者线程启动成功",index);
    cout<<charTemp<<endl;
    syslog(LOG_INFO,charTemp);
    
    //while(count < 10)
   // {
        bzero(charTemp,128);
        sprintf(charTemp,"第[%d]号生产者线程(1)",index);
        cout<<charTemp<<endl;
        syslog(LOG_INFO,charTemp);

        unique_lock<mutex> lc(mtlock);
        //mtlock.lock();

        bzero(charTemp,128);
        sprintf(charTemp,"第[%d]号生产者线程(2)",index);
        cout<<charTemp<<endl;
        syslog(LOG_INFO,charTemp);

        cvlock.wait(lc,[]{ if(temp.size() < MAX_SIZE) return true; else return false;});

        bzero(charTemp,128);
        sprintf(charTemp,"第[%d]号生产者线程(3)",index);
        cout<<charTemp<<endl;
        syslog(LOG_INFO,charTemp);

        writeVal = index*10+count;

        bzero(charTemp,128);
        sprintf(charTemp,"第[%d]号生产者线程写入数据（%d）",index,writeVal);
        cout<<charTemp<<endl;
        syslog(LOG_INFO,charTemp);

        temp.emplace(writeVal);

        //mtlock.unlock();
        cvlock.notify_all();
        count++;
        this_thread::sleep_for(std::chrono::milliseconds(1000));
   // }
        bzero(charTemp,128);
        sprintf(charTemp,"第[%d]号生产者线程退出成功",index);
        cout<<charTemp<<endl;
        syslog(LOG_INFO,charTemp);
}

void Cousomer(int index)
{
    char charTemp[128];
    
    bzero(charTemp,128);
    sprintf(charTemp,"第[%d]号消费者线程启动成功",index);
    cout<<charTemp<<endl;
    syslog(LOG_INFO,charTemp);
    
    while(true)
    {
        bzero(charTemp,128);
        sprintf(charTemp,"第[%d]号消费者线程（1）",index);
        cout<<charTemp<<endl;
        syslog(LOG_INFO,charTemp);
    
        unique_lock<mutex> lc(mtlock);
        //mtlock.lock();
        bzero(charTemp,128);
        sprintf(charTemp,"第[%d]号消费者线程（2）",index);
        cout<<charTemp<<endl;
        syslog(LOG_INFO,charTemp);
                
        cvlock.wait(lc,[](){ if(temp.size() > 0) return true; else return false; });

        bzero(charTemp,128);
        sprintf(charTemp,"第[%d]号消费者线程（3）",index);
        cout<<charTemp<<endl;
        syslog(LOG_INFO,charTemp); 

        int val = temp.front();        
        temp.pop();
        //mtlock.unlock();
        cvlock.notify_all();
    }

    bzero(charTemp,128);
    sprintf(charTemp,"第[%d]号消费者线程关闭",index);
    cout<<charTemp<<endl;
    syslog(LOG_INFO,charTemp);
}

void go()
{
    unique_lock<mutex> lc(mtlock);
    isReady = true;
    cvlock.notify_all();
}

//线程测试函数
void ThreadTest(int index)
{
    cout<<"["<<index<<"]号线程启动成功"<<endl;

    unique_lock<mutex> lc(mtlock);
    cout<<"["<<index<<"]号线程解锁"<<endl;
    cvlock.wait(lc,[](){ return isReady;});
    iValue++;
    cout<<"["<<index<<"]号线程("<<iValue<<")"<<endl;
}

